package tool

import play.api.libs.json.Json
import tool.Pojo.MissionData

import java.io.File
import scala.collection.mutable
import implicits.Implicits._
import models.Tables._
import org.apache.commons.io.FileUtils
import utils.Utils

/**
 * Created by yz on 26/9/2021
 */
trait ProjectTool {

  def getCds(file: File) = {
    val map = Tool.getSeqMap(file)
    map.map { case (key, cds) =>
      val id = key.split("\\s+")(0).replaceAll("^>", "")
      CdsRow(id, cds)
    }.toList
  }

  def getBasic344Cds(file: File) = {
    val map = Tool.getSeqMap(file)
    map.map { case (key, cds) =>
      val id = key.split("gene=").last.trim
      Basic344CdsRow(id, cds)
    }.toList
  }

  def getPeps(file: File) = {
    val map = Tool.getSeqMap(file)
    map.map { case (key, cds) =>
      val id = key.split("\\s+")(0).replaceAll("^>", "")
      PepRow(id, cds)
    }.toList
  }

  def getBasic344Peps(file: File) = {
    val map = Tool.getSeqMap(file)
    map.map { case (key, cds) =>
      val id = key.split("gene=").last.trim
      Basic344PepRow(id, cds)
    }.toList
  }

  def getSeqMap(file: File) = {
    val map = mutable.LinkedHashMap[String, String]()
    var key = ""
    file.lines.foreach { line =>
      if (line.startsWith(">")) {
        key = line
        map += (key -> "")
      } else if (key != "") {
        map(key) += line
      }
    }
    map
  }

  def getDbFile(againstType: String) = {
    againstType match {
      case "macadamiaGene" => new File(Tool.seqsDir, "macadamia.cds.fa")
      case "macadamiaGenome" => new File(Tool.seqsDir, "macadamia.genome.fa")
      case "mintegChloroplastGenome" => new File(Tool.seqsDir, "minteg_chloroplast.fa")
      case "mintegMitochondrionGenome" => new File(Tool.seqsDir, "minteg_mitochondrion.fa")
      case "minteg2022Genome" => new File(Tool.seqsDir, "minteg_2022.genome.fa")
      case "macadamiaPep" => new File(Tool.seqsDir, "macadamia.pep.fa")
      case "minteg2022Pep" => new File(Tool.seqsDir, "minteg_2022.pep.fa")
      case "mjanseniGenome" => new File(Tool.seqsDir, "mjanseni.fa")
      case "mtetraGenome" => new File(Tool.seqsDir, "mtetra.fa")
      case "mtetraPlastidGenome" => new File(Tool.seqsDir, "mtetra_plastid.fa")
      case "mtetraMitochondrionGenome" => new File(Tool.seqsDir, "mtetra_mitochondrion.fa")
      case "mterniGenome" => new File(Tool.seqsDir, "mterni.fa")
      case "mterniPlastidGenome" => new File(Tool.seqsDir, "mterni_plastid.fa")
      case "mterniMitochondrionGenome" => new File(Tool.seqsDir, "mterni_mitochondrion.fa")
    }
  }

  def getGenomeFile(species: String) = {
    species match {
      case "Macadamia integrifolia" => new File(Tool.seqsDir, "macadamia.genome.fa")
    }
  }

  def dealInputFile(file: File) = {
    val lines = file.lines
    val newLines = lines.map(_.trim)
    newLines.toFile(file)
  }

  def getPrimerResult(tmpDir: File, start: Int): String = {

    val f = new File(tmpDir, "out.txt").lines
    val i = f.filter(_.contains("INTERNAL OLIGO EXCLUDED REGIONS")).head
    val i2 = f.filter(_.contains("KEYS (in order of precedence):")).head

    val s = f.slice(f.indexOf(i) + 2, f.indexOf(i2))

    val seqs = s.grouped(3).map { x =>
      val seq = x.head.split(" ")
      val c1 = "<tr><td class='length'>" + (seq.init.last.toInt + start) + "</td> " +
        seq.last.split("").map(y => "<td>" + y + "</td>").mkString + "</tr>"

      val index = x.head.indexOf(seq.last.head) - 1

      val c2 = "<tr>" + x(1).split("").drop(index).map {
        case y if y == "*" => "<td class='blue'>" + y + "</td>"
        case y if y == "x" => "<td class='blue'>" + y + "</td>"
        case y if y == ">" => "<td class='orange'>" + y + "</td>"
        case y if y == "<" => "<td class='orange'>" + y + "</td>"
        case y if y == "^" => "<td class='orange'>" + y + "</td>"
        case y: String => "<td>" + y + "</td>"
      }.mkString + "</tr>"
      val c3 = "<tr><td>" + x.last + "</td></tr>"
      c1 + c2 + c3
    }.mkString

    val head = "OLIGO            start  len      tm     gc%  any_th  3'_th hairpin seq"
    val t1 = f.indexOf(head) + 1
    val t2 = f.filter(_.contains("SEQUENCE SIZE")).head
    val t = f.slice(t1, f.indexOf(t2))

    val r1 = t.map { x =>
      val td = x.split("\\s+")
      "<tr class='tableText'><td>" + td.take(2).mkString("\t") + "</td><td>" + (td(2).toInt + start) + "</td>" +
        td.drop(3).map { y =>
          "<td>" + y + "</td>"
        }.mkString + "</tr>"
    }.mkString

    val a1 = f.indexOf("ADDITIONAL OLIGOS") + 3
    val a2 = f.indexOf("Statistics")

    val rw = f.slice(a1, a2).grouped(5).map(_.take(3)).toArray
    val r2 = rw.map { x =>
      val array = x.map(_.split("\\s+"))
      val a = array.head.tail +: array.tail

      a.map { td =>
        "<tr><td>" + td.head + "</td><td>" + td.slice(2, 4).mkString("\t") + "</td><td>" + (td(3).toInt + start) + "</td>" +
          td.drop(4).map { y =>
            "<td>" + y + "</td>"
          }.mkString + "</tr>"
      }.mkString
    }.mkString

    val seqSizeIndex = f.indexOf(t2)
    val seqSize = "<p>" + f(seqSizeIndex) + "</p><p>" + f(seqSizeIndex + 1) + "</p><br>"

    val productSize = "<p>" + f(seqSizeIndex + 3) + "</p><p>" + f(seqSizeIndex + 4) + "</p><p>" + f(seqSizeIndex + 5) + "</p>"

    val statIndex = f.indexOf("Statistics")

    val stat = f.slice(statIndex + 4, statIndex + 7).map { x =>
      "<tr>" + x.split("\\s+").map(y => "<td>" + y + "</td>").mkString + "</tr>"
    }.mkString

    val pairIndex = f.indexOf("Pair Stats:")
    val pairStats = f.slice(pairIndex + 1, pairIndex + 3).map(x => "<p>" + x + "</p>")


    val html =
      s"""
         |        <hr>
         |        <h3>Primer design results:</h3>
         |        <div class="table-responsive panel-collapse in " >
         |            <table class="table" style="word-wrap: break-word">
         |                <thead>
         |                    <tr class="tableHead">
         |                        <th data-field="oligos">Oligos</th>
         |                        <th data-field="start">Start position</th>
         |                        <th data-field="length">Length</th>
         |                        <th data-field="tm">Tm</th>
         |                        <th data-field="gc">GC percent</th>
         |                        <th data-field="any">Self any</th>
         |                        <th data-field="end">Self end</th>
         |                        <th data-field="end">Hairpin</th>
         |                        <th data-field="seq">Sequence</th>
         |                    </tr>
         |                </thead>
         |                <tbody>
         |                ${r1.mkString}
         |                </tbody>
         |            </table>
         |        </div>
         |        $seqSize
         |
         |        <div>
         |
         |            <h3>Primer design results in the sequence:</h3>
         |
         |            $productSize
         |            <table>
         |                <tbody id="seq">
         |                ${seqs.mkString}
         |
         |                </tbody>
         |            </table>
         |        </div>
         |
         |
         |        <h3>Note:</h3>
         |        <table>
         |            <tbody>
         |                <tr>
         |                    <td class="blue" style="width: 80px;">xxxxxxx</td>
         |                    <td>excluded region for internal oligo</td>
         |                </tr>
         |                <tr>
         |                    <td class="orange">>>>>>></td>
         |                    <td>left primer</td>
         |                </tr>
         |                <tr>
         |                    <td class="orange"><<<<<<</td>
         |                    <td>right primer</td>
         |                </tr>
         |                <tr>
         |                    <td class="orange">^^^^^^^^</td>
         |                    <td>right primer</td>
         |                </tr>
         |
         |            </tbody>
         |        </table>
         |
         |
         |        <h3>ADDITIONAL OLIGOS:</h3>
         |        <div class="table-responsive panel-collapse in " >
         |            <table class="table table-hover table-striped" style="word-wrap: break-word">
         |                <thead>
         |                    <tr>
         |                    <th></th>
         |                        <th>Oligos</th>
         |                        <th>Start position</th>
         |                        <th>Length</th>
         |                        <th>Tm</th>
         |                        <th>GC percent</th>
         |                        <th>Self any</th>
         |                        <th>Self end</th>
         |                        <th>Hairpin</th>
         |                        <th>Sequence</th>
         |                    </tr>
         |                </thead>
         |                <tbody id="additionalTable">
         |                ${r2.mkString}
         |
         |                </tbody>
         |            </table>
         |        </div>
         |
         |        <h3>Statistics:</h3>
         |        <div class="table-responsive panel-collapse in " >
         |            <table class="table table-hover table-striped" style="word-wrap: break-word">
         |                <thead>
         |                    <tr>
         |                        <th>Direction</th>
         |                        <th>Considered</th>
         |                        <th>Too many Ns</th>
         |                        <th>In target</th>
         |                        <th>In excel reg</th>
         |                        <th>Not ok reg</th>
         |                        <th>Bad GC%</th>
         |                        <th>No GC clamp</th>
         |                        <th>TM too low</th>
         |                        <th>TM too high</th>
         |                        <th>High any_th compl</th>
         |                        <th>High 3'_th compl</th>
         |                        <th>Highhair-pin</th>
         |                        <th>Poly x</th>
         |                        <th>High end stab</th>
         |                        <th>Ok</th>
         |                    </tr>
         |                </thead>
         |                <tbody id="additionalTable">
         |                $stat
         |
         |
         |                </tbody>
         |            </table>
         |        </div>
         |
         |
         |        <h3>Pair Stats:</h3>
         |       ${pairStats.mkString}
    """.stripMargin

    html

  }

  def getNonePrimerResult(tmpDir: File, start: Int): String = {
    val f = new File(tmpDir, "out.txt").lines

    val i = f.filter(_.contains("INTERNAL OLIGO EXCLUDED REGIONS")).head
    val i2 = f.filter(_.contains("KEYS (in order of precedence):")).head

    val s = f.slice(f.indexOf(i) + 2, f.indexOf(i2))

    val seqs = s.grouped(3).map { x =>
      val seq = x.head.split(" ")
      val c1 = "<tr><td class='length'>" + (seq.init.last.toInt + start) + "</td> " +
        seq.last.split("").map(y => "<td>" + y + "</td>").mkString + "</tr>"

      val index = x.head.indexOf(seq.last.head) - 1

      val c2 = "<tr>" + x(1).split("").drop(index).map {
        case y if y == "*" => "<td class='blue'>" + y + "</td>"
        case y if y == "x" => "<td class='blue'>" + y + "</td>"
        case y if y == ">" => "<td class='orange'>" + y + "</td>"
        case y if y == "<" => "<td class='orange'>" + y + "</td>"
        case y if y == "^" => "<td class='orange'>" + y + "</td>"
        case y: String => "<td>" + y + "</td>"
      }.mkString + "</tr>"
      val c3 = "<tr><td>" + x.last + "</td></tr>"
      c1 + c2 + c3
    }.mkString

    val t2 = f.filter(_.contains("SEQUENCE SIZE")).head

    val seqSizeIndex = f.indexOf(t2)
    val seqSize = "<p>" + f(seqSizeIndex) + "</p><p>" + f(seqSizeIndex + 1) + "</p><br>"

    val productSize = "<p>" + f(seqSizeIndex + 3) + "</p><p>" + f(seqSizeIndex + 4) + "</p><p>" + f(seqSizeIndex + 5) + "</p>"

    val statIndex = f.indexOf("Statistics")

    val stat = f.slice(statIndex + 4, statIndex + 7).map { x =>
      "<tr>" + x.split("\\s+").map(y => "<td>" + y + "</td>").mkString + "</tr>"
    }.mkString

    val pairIndex = f.indexOf("Pair Stats:")
    val pairStats = f.slice(pairIndex + 1, pairIndex + 3).map(x => "<p>" + x + "</p>")


    val html =
      s"""
         |        <hr>
         |        <h3>NO PRIMERS FOUND</h3>
         |        </div>
         |        $seqSize
         |
         |        <div>
         |            $productSize
         |            <table>
         |                <tbody id="seq">
         |                ${seqs.mkString}
         |
         |                </tbody>
         |            </table>
         |        </div>
         |
         |
         |        <h3>Note:</h3>
         |        <table>
         |            <tbody>
         |                <tr>
         |                    <td class="blue" style="width: 80px;">xxxxxxx</td>
         |                    <td>excluded region for internal oligo</td>
         |                </tr>
         |            </tbody>
         |        </table>
         |
         |<br/>
         |
         |        <h3>Statistics:</h3>
         |        <div class="table-responsive panel-collapse in " >
         |            <table class="table table-hover table-striped" style="word-wrap: break-word">
         |                <thead>
         |                    <tr>
         |                        <th>Direction</th>
         |                        <th>Considered</th>
         |                        <th>Too many Ns</th>
         |                        <th>In target</th>
         |                        <th>In excel reg</th>
         |                        <th>Not ok reg</th>
         |                        <th>Bad GC%</th>
         |                        <th>No GC clamp</th>
         |                        <th>TM too low</th>
         |                        <th>TM too high</th>
         |                        <th>High any_th compl</th>
         |                        <th>High 3'_th compl</th>
         |                        <th>Highhair-pin</th>
         |                        <th>Poly x</th>
         |                        <th>High end stab</th>
         |                        <th>Ok</th>
         |                    </tr>
         |                </thead>
         |                <tbody id="additionalTable">
         |                $stat
         |
         |
         |                </tbody>
         |            </table>
         |        </div>
         |
         |
         |        <h3>Pair Stats:</h3>
         |       ${pairStats.mkString}
    """.stripMargin
    html
  }

}
